package club.gggd.security_jwt_demo.service.impl;

import club.gggd.security_jwt_demo.mapper.RoleMapper;
import club.gggd.security_jwt_demo.mapper.UserMapper;
import club.gggd.security_jwt_demo.pojo.dto.UserPermission;
import club.gggd.security_jwt_demo.pojo.dto.UserRoleDto;
import club.gggd.security_jwt_demo.pojo.entity.SysUser;
import club.gggd.security_jwt_demo.pojo.module.BusinessException;
import club.gggd.security_jwt_demo.pojo.module.ResultCode;
import club.gggd.security_jwt_demo.pojo.vo.LoginVo;
import club.gggd.security_jwt_demo.service.UserService;
import club.gggd.security_jwt_demo.util.JwtUtil;
import club.gggd.security_jwt_demo.util.UserProvider;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author srx
 * @date 2023/12/9 14:39
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, SysUser> implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Resource
    private BCryptPasswordEncoder passwordEncoder;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private AuthenticationManagerBuilder authenticationManagerBuilder;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private UserProvider userProvider;

    @Override
    public String login(LoginVo vo) {
        // 判断用户
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getAccount, vo.getAccount());
        SysUser user = userMapper.selectOne(wrapper);
        Optional.ofNullable(user).orElseThrow(() -> new BusinessException(ResultCode.USER_NOT_FOUND));
        boolean matches = passwordEncoder.matches(vo.getPassword(), user.getPassword());
        if (!matches) {
            throw new BusinessException(ResultCode.USER_CREDENTIALS_ERROR);
        }
        // 组装Authentication
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(vo.getAccount(), vo.getPassword());
        Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        String token = jwtUtil.generateToken(user);
        return token;
    }


    @Override
    public SysUser getUserInfo(String account) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getAccount, account);
        SysUser user = userMapper.selectOne(wrapper);
        return user;
    }

    @Override
    public List<SimpleGrantedAuthority> getAuthList(Integer userId) {
        // 获取该用户所有权限
        List<UserPermission> list = userMapper.getUserPermissionList(userId);
        Set<String> permission = list.stream().map(UserPermission::getPermissionCode).collect(Collectors.toSet());
        // 获取该用户所有角色
        List<UserRoleDto> userRoleList = roleMapper.getUserRoleList(userId);
        for (UserRoleDto ur : userRoleList) {
            permission.add(ur.getRoleCode());
        }
        List<SimpleGrantedAuthority> authorities = permission.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
        return authorities;
    }

    @Override
    public SysUser getUserByAccount(String account) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getAccount, account);
        SysUser user = userMapper.selectOne(wrapper);
        return user;
    }
}
